<?php

namespace App\Http\Controllers\Api\V1;

use App\Library\AdvancedRateLimiter;
use App\Models\Device;
use App\Models\User;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Facades\JWTAuth;

/**
 * 用户登录
 * Class LoginController
 * @package App\Http\Controllers\Api
 */
class LoginController extends BaseController
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * 最多错误次数
     * @var int
     */
    protected $maxAttempts = 3;

    /**
     * 错误间隔时间(分钟)
     * @var int
     */
    protected $decayMinutes = [1, 3, 10, 60, 600];

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest:api')->except(['logout', 'refresh']);
    }

    /**
     * Handle a login request to the application.
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response|void
     * @throws \Illuminate\Validation\ValidationException
     */
    public function login(Request $request)
    {
        $this->validateLogin($request);
        $userAgency = User::where($this->username(), $request->input($this->username()))->value("agency_id");
        $deviceAgency = Device::where("code", $request->input("device_code"))->value("agency_id");

        if ($userAgency != $deviceAgency) {
            /* 增加错误次数 */
            $this->incrementLoginAttempts($request);
            return $this->json([], config("apicode.verifyDeviceFail.msg"), config("apicode.verifyDeviceFail.code"));
        }
        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }

        if ($token = $this->guard()->attempt($this->credentials($request))) {

            $request->offsetSet('token', $token);


            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }
    /**
     * Get the failed login response instance.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws ValidationException
     */
    protected function sendFailedLoginResponse(Request $request)
    {
        /*
        throw ValidationException::withMessages([
            $this->username() => [trans('auth.failed')],
        ]);
        */

        return  $this->json([], config("apicode.loginFail.msg"),config("apicode.loginFail.code"));
    }
    /**
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh(Request $request)
    {
        $this->validate($request, [
            'token' => 'required'
        ]);

        try {
            $token = $this->guard()->refresh();
            return $this->json([
                'token' => $token
            ], 'Token成功刷新');
        } catch (JWTException $exception) {
            return $this->json([], '抱歉，Token刷新失败', 50000);
        }
    }

    /**
     *
     * @Date 2020/11/1 下午3:21
     *
     */
    public function userProfile() {
        return response()->json(auth()->user());
    }
    /**
     * Log the user out of the application.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout(Request $request)
    {
        $this->validate($request, [
            'token' => 'required'
        ]);

        try {
            $this->guard()->logout();
            return $this->json([], '用户成功注销');
        } catch (JWTException $exception) {
            return $this->json([], '抱歉，用户无法注销', 50000);
        }
    }
    /**
     * Increment the login attempts for the user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return void
     */
    protected function incrementLoginAttempts(Request $request)
    {
        $this->limiter()->hit(
            $this->throttleKey($request), array_map(function ($decayMinute) {
                return (int) ($decayMinute * 60);
            }, (array) $this->decayMinutes())
        );
    }

    /**
     * Validate the user login request.
     *
     * @param \Illuminate\Http\Request $request
     * @return void
     */
    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'required|numeric',
            $this->username() => 'regex:/^1[345789][0-9]{9}$/',     //正则验证
            'password' => 'required|string',
            'device_code'=>'required|exists:devices,code'
        ], [], []);
    }

    /**
     * Get the guard to be used during authentication.
     *
     * @return \Tymon\JWTAuth\JWTGuard
     */
    protected function guard()
    {
        return Auth::guard('api');
    }

    /**
     * Where to redirect users after login.
     *
     * @return string
     */
    protected function redirectTo()
    {
        return route('api.index');
    }

    /**
     * 更改高级设置登录错误次数
     * @return \Illuminate\Foundation\Application|mixed
     */
    protected function limiter()
    {
        return app(AdvancedRateLimiter::class);
    }
    /**
     * Get the login username to be used by the controller.
     *
     * @return string
     */
    public function username()
    {
        return 'phone';
    }
    /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLoginResponse(Request $request)
    {

        $token = $request->offsetGet('token');

        $this->clearLoginAttempts($request);

        return $this->json([

            'access_token' => $token,

            'token_type' => 'bearer',

            'expires_in' => JWTAuth::factory()->getTTL() * 60

        ]);
    }
}
